/*
 * @(#)AopContext.java    Aug 16, 2010
 *
 * Copyright 2009 Nyber(Shanghai Itd. All rights reserved.
 */

package com.lab.aop;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;

/**
 * Class description goes here.
 *
 * @author nickevin@gmail.com
 * @version Aug 16, 2010 3:13:20 PM
 */

public class AopContext {

    private ClassLoader classLoader = AopContext.class.getClassLoader();
    private static AopContext instance = new AopContext();
    private Set<Annotation> classLevelAnnotations = new HashSet<Annotation>();

    public static AopContext getInstance() {
        return instance;
    }

    private AopContext() {}

    public void init(File file) throws Exception {
        String pkgName = getPkgName(file);

        File[] classFiles = file.listFiles();
        for (File classFile : classFiles) {
            resolveClass(pkgName, classFile);
        }
    }

    private void resolveClass(String pkgName, File classFile) throws Exception {
        Class clazz = classLoader.loadClass(pkgName
                + FilenameUtils.getBaseName(classFile.getName()));
        if (!clazz.isAnnotation()) {
            Annotation[] annotations = clazz.getAnnotations();
            for (Annotation annotation : annotations) {
                if (classAnnotationMatches(annotation)) {
                    classLevelAnnotations.add(annotation);
                    resolveMethod(clazz);
                }
            }
        }
    }

    private void resolveMethod(Class clazz) throws Exception {
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            Before beforeAnnotation = method.getAnnotation(Before.class);
            After afterAnnotation = method.getAnnotation(After.class);
            Around aroundAnnotation = method.getAnnotation(Around.class);
            if (beforeAnnotation != null) {
                resolveBeforeAnnotation(beforeAnnotation);
            }
        }
    }

    private void resolveBeforeAnnotation(Before annotation) {}

    private boolean methodAnnotationMatches(Annotation annotation) {
        String name = annotation.annotationType().getSimpleName();

        return "Before".equals(name) || "Around".equals(name)
                || "After".equals(name);
    }

    private boolean classAnnotationMatches(Annotation annotation) {
        return "Aspect".equals(annotation.annotationType().getSimpleName());
    }

    private static String getPkgName(File file) {
        String pkg = StringUtils.substringAfter(file.getAbsolutePath(),
                "classes");
        pkg = pkg.replace("\\", ".");

        return pkg.substring(1) + ".";
    }

}
